﻿using System;

using System.Collections.Generic;
using System.Text;
using Silvermoon.Controls.Base;

namespace Silvermoon.Controls.Classes
{
    /// <summary>
    /// Collection class for ListViews.
    /// </summary>
    public class VirtualItemCollection : IList<ItemBase>
    {
        #region fields

        private ItemBase[] items;
        private int[] offsets;
        private ListViewBase listView;
        private int count = 0;
        private List<int> headers;

        #endregion
        #region ctor

        public VirtualItemCollection(ListViewBase listView)
            : base()
        {
            this.listView = listView;
            ItemHeight = 64;
            headers = new List<int>();
        }

        #endregion
        #region props

        public int Capacity { get { return items != null ? items.Length : 0; } }
        public int ItemHeight { get; set; }

        #endregion
        #region IList<ItemBase> Members

        public int IndexOf(ItemBase item)
        {
            return Array.IndexOf(items, item, 0, count);
        }

        public void Insert(int index, ItemBase item)
        {
            throw new NotImplementedException();
        }

        public void RemoveAt(int index)
        {
            ItemBase item = items[index];
            item.Removing();

            ItemHeader header = item as ItemHeader;
            if (header != null) headers.Remove(index);

            listView.ItemRemoved(index, item);

            count--;
            if (index < count)
            {
                Array.Copy(items, index + 1, items, index, this.count - index);
            }
            items[count] = null;

            SetOffsets(index);
            listView.OnDetachItem(index, item);
            item.ListView = null;
        }

        public ItemBase this[int index]
        {
            get
            {
                ItemBase item = items[index];
                if (item == null)
                {
                    item = listView.OnAttachItem(index);
                    items[index] = item;
                    item.ListView = listView;
                    if (!Initializing)
                    {
                        SetOffsets(index);
                    }
                    else
                    {
                        min = Math.Min(min, index);
                    }
                    ItemHeader header = item as ItemHeader;
                    if (header != null && !headers.Contains(index)) AddHeader(index);
                    listView.ItemAdded(index);

                }
                return item;
            }
            set
            {
                if (index >= Capacity) Extend(index);
                items[index] = value;
                ItemHeader header = value as ItemHeader;
                if (header != null) AddHeader(index);
            }
        }

        private void AddHeader(int index)
        {
            if (!headers.Contains(index))
            {
                headers.Add(index);
                headers.Sort();
            }
        }

        #endregion
        #region ICollection<ItemBase> Members

        public void Add(ItemBase item)
        {
            item.ListView = listView;
            ItemHeader header = item as ItemHeader;
            if (header != null) AddHeader(count);
            if (count <= Capacity) Extend(count);
            int offset = count > 0 ? offsets[count - 1] : 0;
            offsets[count] = item.Height + offset;
            items[count++] = item;
            item.Inserting();
            listView.ItemAdded(count - 1);
        }

        private void SetOffsets(int index)
        {
            int offset = index > 0 ? offsets[index - 1] : 0;
            for (int i = index; i < count; i++)
            {
                ItemBase item = items[i];
                int h = item != null ? item.Height : ItemHeight;
                offset += h;
                offsets[i] = offset;
            }
        }

        private void Extend(int size)
        {
            int n = ((size + 64) >> 6) << 6;
            ItemBase[] newItems = new ItemBase[n];
            int[] newOffsets = new int[n];
            if (items != null && count > 0)
            {
                Array.Copy(items, newItems, count);
                Array.Copy(offsets, newOffsets, count);
            }
            items = newItems;
            offsets = newOffsets;

        }

        public void Clear()
        {
            count = 0;
            headers.Clear();
            if (Capacity > 24)
            {
                items = new ItemBase[24];
                offsets = new int[24];
            }
            listView.TopOffset = 0;
            if (!Initializing)
            {
                listView.Invalidate(InvalidationFlag.LayoutAppearance);
            }
        }

        public bool Contains(ItemBase item)
        {
            return Array.IndexOf(items, item) >= 0;
        }

        public void CopyTo(ItemBase[] array, int arrayIndex)
        {
            throw new NotImplementedException();
        }

        public int ItemCount
        {
            get { return count; }
            set
            {
                if (Capacity < value) Extend(value);
                count = value;
                if (Initializing) min = 0; else SetOffsets(0);
            }
        }

        public int Count { get { return ItemCount; } }

        public bool IsReadOnly
        {
            get { return false; }
        }

        public bool Remove(ItemBase item)
        {
            int index = IndexOf(item);
            if (index >= 0)
            {
                RemoveAt(index);
                return true;
            }
            return false;
        }

        #endregion
        #region IEnumerable<ItemBase> Members

        public IEnumerator<ItemBase> GetEnumerator()
        {
            return new VirtualItemEnumerator(this);
        }

        #endregion
        #region IEnumerable Members

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return new VirtualItemEnumerator(this);
        }

        #endregion
        #region IItemList Members

        public int GetOffset(int index)
        {
            return index > 0 ? offsets[index - 1] : 0;
        }

        public int GetItemIndexFromTop(int top)
        {
            if (count > 0)
            {
                int index = Array.BinarySearch<int>(offsets, 0, count, top);
                if (index < 0) index = -1 - index;
                return index;
            }
            else return -1;

        }

        public IEnumerable<ItemBase> GetAvailableItems()
        {
            for (int i = 0; i < count; i++)
            {
                ItemBase item = items[i];
                if (item != null) yield return item;
            }
        }

        public int GetHeaderIndexAboveIndex(int index)
        {
            for (int i = headers.Count - 1; i >= 0; i--)
            {
                int headerIndex = headers[i];
                if (headerIndex <= index) return headerIndex;
            }
            return -1;
        }

        public int TotalHeight { get { return count > 0 ? offsets[count - 1] : 0; } }

        private bool initializing;
        private int min;

        public bool Initializing
        {
            get { return initializing; }
            set
            {
                if (initializing != value)
                {
                    initializing = value;
                    if (value) min = int.MaxValue;
                    else if (min < count) SetOffsets(min);
                }
            }
        }

        #endregion

        public void UpdateHeight(ItemBase item)
        {
            int index = IndexOf(item);
            if (index >= 0)
            {
                SetOffsets(index);
            }
        }

    }
}
